using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using mesoBoard.Data.Repositories;
using mesoBoard.Data;
using System.IO;
using mesoBoard.Web;
using mesoBoard.Web.Core;
using mesoBoard.Services;
using mesoBoard.Common;

namespace mesoBoard.Web.Controllers
{
    [Authorize]
    public partial class PostController : mesoBoardController
    {
        public PostController()
        {
        }

        public ActionResult GetSmilies(int x, int z)
        {
            ViewData["x"] = x;
            ViewData["z"] = z;
            IEnumerable<Smiley> Smilies = Repositories.Smilies.GetSmilies();
            if (Smilies.Count() < z)
            {
                ViewData["z"] = Smilies.Count();
                return View(Smilies);
            }
            else
            {
                return View(Smilies.Take(z));
            }
        }

        [HttpGet]
        public ActionResult CreateThread(int ForumID)
        {
            Forum TheForum = Repositories.Forums.GetForum(ForumID);

            if (!mbServices.Forums.CanCreateThread(ForumID, CurrentUser.UserID))
            {
                SetNotice("You don't have permission to create a thread in this forum");
                return RedirectToAction("ViewForum", "Board", new { ForumID = ForumID });
            }

            ViewData["BreadCrumb"] = "Create Thread";
            ViewData["ForumID"] = ForumID;
            ViewData["UserPermissions"] = new Models.UserPermissions(CurrentUser, TheForum);
            return View();

        }

        [HttpPost]
        [ValidateInput(false)]
        [ValidateAntiForgeryToken]
        public ActionResult CreateThread(
            Post FirstPost,
            int ForumID,
            string PollText,
            string PollOptions,
            int ThreadType = 1,
            bool SubscribeToThread=false,
            bool Preview=false,
            string Image=null)
        {
            Forum TheForum = Repositories.Forums.GetForum(ForumID);

            ViewData["UserPermissions"] = new Models.UserPermissions(CurrentUser, Repositories.Forums.GetForum(ForumID));

            if (CurrentUser.LastPostDate.HasValue)
            {
                int MinTimeLimit =  int.Parse(SiteConfig.TimeBetweenPosts.Value);
                double ValToCompare = (DateTime.UtcNow - CurrentUser.LastPostDate.Value).TotalSeconds;
                if (ValToCompare < MinTimeLimit)
                    ModelState.AddModelError("TimeBetweenPosts", "You may only create new posts every " + MinTimeLimit + " seconds (" + Math.Round((MinTimeLimit - ValToCompare)) + " seconds remaining)");
            }

            string[] splitOptions = null;
            if (!string.IsNullOrEmpty(PollText))
            {
                if (string.IsNullOrEmpty(PollOptions))
                    ModelState.AddModelError("PollOptions", "The poll must have options");
                else
                {
                    splitOptions = PollOptions.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

                    if (splitOptions.Count() < 2)
                        ModelState.AddModelError("PollOptions", "Minimum two poll options");
                }
            }

            if (Request.Files.Count > 0)
            {
                ValidatePostedFiles();
            }

            ViewData["BreadCrumb"] = "Create Thread";

            ValidateThread(FirstPost);

            ViewData["ForumID"] = ForumID;
            ViewData["Preview"] = Preview;

            if (!string.IsNullOrWhiteSpace(FirstPost.Text))
            {
                // FirstPost.Text = FirstPost.Text;
                FirstPost.ParsedText = mbServices.Posts.ParseBBCodeText(FirstPost.Text);
            }

            if (Preview)
            {
                return View(FirstPost);
            }
            else if (ModelState.IsValid)
            {
                Thread TheThread = mbServices.Threads.CreateThread(ForumID, CurrentUser.UserID, ThreadType, Image, FirstPost, PollText, splitOptions, Request.Files);

                if (mbServices.Threads.IsSubscribed(TheThread.ThreadID, CurrentUser.UserID) && SubscribeToThread)
                    mbServices.Threads.Subscribe(TheThread.ThreadID, CurrentUser.UserID);

                SetSuccess("Thread Created");
                return RedirectToAction("ViewThread", "Board", new { ThreadID = TheThread.ThreadID });
            }
            else
            {
                SetError("Invalid thread information");
                return View();
            }
        }

        [HttpGet]
        public ActionResult CreatePost(int ThreadID, int QuotePostID=0)
        {
            Thread TheThread = mbServices.Threads.GetThread(ThreadID);
            Forum TheForum = TheThread.Forum;

            if (!mbServices.Forums.CanReply(TheForum.ForumID, CurrentUser.UserID))
            {
                if (TheThread.IsLocked)
                {
                    SetNotice("You can't reply to this thread because it is locked");
                    return RedirectToAction("ViewThread", "Board", new { ThreadID = ThreadID });
                }
                else
                {
                    SetNotice("You don't have permission to reply in this forum");
                    return RedirectToAction("ViewForum", "Board", new { ForumID = TheForum.ForumID });
                }
            }

            if (QuotePostID != 0)
            {
                Post QuotePost = Repositories.Posts.GetPost(QuotePostID);
                ViewData["QuotePostText"] =
                    "[quote=" + QuotePost.User.Username + "]" + QuotePost.Text + "[/quote]";
            }

            ViewData["UserPermissions"] = new Models.UserPermissions(CurrentUser, TheForum);

            ViewData["BreadCrumb"] = "Post Reply";
            ViewData["ThreadID"] = ThreadID;
            return View();
        }

        [HttpPost]
        [ValidateInput(false)]
        [ValidateAntiForgeryToken]
        public ActionResult CreatePost(Post ThePost, int ThreadID, bool Preview=false, bool SubscribeToThread=false)
        {
            Thread TheThread = mbServices.Threads.GetThread(ThreadID);

            ViewData["BreadCrumb"] = "Post Reply";
            ViewData["TheThread"] = TheThread;
            ViewData["ThreadID"] = ThreadID;

            ValidatePost(ThePost);

            Forum TheForum = TheThread.Forum;

            ViewData["UserPermissions"] = new Models.UserPermissions(CurrentUser, TheForum);

            if (CurrentUser.LastPostDate.HasValue)
            {
                int MinTimeLimit =  SiteConfig.TimeBetweenPosts.ToInt();
                double ValToCompare = (DateTime.UtcNow - CurrentUser.LastPostDate.Value).TotalSeconds;
                if (ValToCompare < MinTimeLimit)
                    ModelState.AddModelError("TimeBetweenPosts", "You may only create new posts every " + MinTimeLimit + " seconds ("+ Math.Round((MinTimeLimit - ValToCompare)) +" remaining)");
            }

            if (Request.Files.Count > 0)
            {
                ValidatePostedFiles();
            }

            if (!string.IsNullOrWhiteSpace(ThePost.Text))
            {
                //ThePost.Text = ThePost.Text;
                ThePost.ParsedText = mbServices.Posts.ParseBBCodeText(ThePost.Text);
            }
            ViewData["Preview"] = Preview;
            if (Preview)
            {
                return View(ThePost);
            }
            else if (ModelState.IsValid)
            {
                if (mbServices.Threads.IsSubscribed(TheThread.ThreadID, CurrentUser.UserID) && SubscribeToThread)
                    mbServices.Threads.Subscribe(TheThread.ThreadID, CurrentUser.UserID);

                mbServices.Posts.CreatePost(ThePost, ThreadID, Request.Files);

                string PostURL = Url.Action("ViewThread", "Board", new { ThreadID = ThePost.ThreadID, PostID = ThePost.PostID }) + "#" + ThePost.PostID;
                Emailing.NewPostEmail(Repositories.Threads.GetSubscriptions(ThreadID), ThePost, ThePost.Thread, PostURL);

                SetSuccess("Your reply was posted");
                return Redirect(Url.Action("ViewThread", "Board", new { ThreadID = ThreadID, LastPost = true, NewPost = true }) + "#" + ThePost.PostID);
            }
            else
            {
                SetError("Post valdiation errors");
                return View();
            }
        }

        [HttpGet]
        public ActionResult EditPost(int PostID)
        {
            Post ThePost = mbServices.Posts.GetPost(PostID);

            if (ThePost.Thread.FirstPostID == PostID)
                return RedirectToAction("EditThread", new { ThreadID = ThePost.ThreadID });

            Thread TheThread = mbServices.Threads.GetThread(ThePost.ThreadID);

            ViewData["TheThread"] = TheThread;
            ViewData["BreadCrumb"] = "Edit Post";
            ViewData["TheAttachments"] = mbServices.Files.GetPostAttachments(PostID);
            ViewData["IsSubscribed"] = mbServices.Threads.IsSubscribed(TheThread.ThreadID, CurrentUser.UserID);
            ViewData["UserPermissions"] = new Models.UserPermissions(CurrentUser, TheThread.Forum);

            if (ThePost != null || mbServices.Posts.CanEditPost(ThePost.PostID, CurrentUser.UserID))
            {
                ThePost.Text = Server.HtmlDecode(ThePost.Text);
                return View(ThePost);
            }
            else
            {
                SetError("You can't edit this post");
                return RedirectToAction("ViewThread", "Board", new { ThreadID = ThePost.ThreadID });
            }
        }

        [HttpPost]
        [ValidateInput(false)]
        [ValidateAntiForgeryToken]
        public ActionResult EditPost(Post ThePost, int[] DeleteAttachments, bool Preview = false)
        {
            Thread TheThread = mbServices.Threads.GetThread(ThePost.ThreadID);
            Post originalPost = mbServices.Posts.GetPost(ThePost.PostID);
            Forum TheForum = TheThread.Forum;
            
            ViewData["TheAttachments"] = mbServices.Files.GetPostAttachments(ThePost.PostID);
            ViewData["BreadCrumb"] = "Edit Post";
            ViewData["UserPermissions"] = new Models.UserPermissions(CurrentUser, TheForum);
            ViewData["TheThread"] = TheThread;
            ViewData["IsSubscribed"] = mbServices.Threads.IsSubscribed(TheThread.ThreadID, CurrentUser.UserID);

            ValidatePost(ThePost);

            if (Request.Files.Count > 0)
            {
                ValidatePostedFiles();
            }

            if (!string.IsNullOrWhiteSpace(ThePost.Text))
            {
                ThePost.ParsedText = mbServices.Posts.ParseBBCodeText(ThePost.Text);
                originalPost.Text = ThePost.Text;
                originalPost.ParsedText = ThePost.ParsedText;
            }

            ViewData["Preview"] = Preview;
            if (Preview)
            {
                ThePost.Thread = TheThread;
                return View(ThePost);
            }
            else if (ModelState.IsValid)
            {
                if (DeleteAttachments != null)
                    mbServices.Files.DeleteAttachments(DeleteAttachments);

                mbServices.Posts.UpdatePost(originalPost, Request.Files);

                SetSuccess("Post edited");
                return Redirect(Url.Action("ViewThread", "Board", new { ThreadID = ThePost.ThreadID, LastPost = true, PostID = ThePost.PostID}) + "#" + ThePost.PostID);
            }
            else
            {
                SetError("Post valdiation errors");
                return View(ThePost);
            }
        }

        [HttpGet]
        public ActionResult EditThread(int ThreadID)
        {
            ViewData["BreadCrumb"] = "Edit Thread";

            Thread TheThread = mbServices.Threads.GetThread(ThreadID); 
            Post ThePost = TheThread.FirstPost;

            if (ThePost == null || !mbServices.Posts.CanEditPost(ThePost.PostID, CurrentUser.UserID))
            {
                SetError("You can't edit this post");
                return RedirectToAction("ViewThread", "Board", new { ThreadID = TheThread.ThreadID });
            }

            ViewData["UserPermissions"] = new Models.UserPermissions(CurrentUser, TheThread.Forum);
            ViewData["TheThread"] = TheThread;
            ViewData["HasVotes"] = false;
            ViewData["TheAttachments"] = mbServices.Files.GetPostAttachments(ThePost.PostID);

            if (ThePost.Thread.Poll != null)
            {
                Poll ThePoll = ThePost.Thread.Poll;
                ViewData["HasVotes"] = Repositories.Polls.HasVotes(ThePoll.PollID);
                ViewData["PollText"] = Server.HtmlDecode(ThePoll.Question);
                ViewData["PollOptions"] = Server.HtmlDecode(ThePoll.PollOptionsAsString());
            }

            ThePost.Title = Server.HtmlDecode(ThePost.Title);
            ThePost.Text = Server.HtmlDecode(ThePost.Text);
            return View(ThePost);
        }

        [HttpPost]
        [ValidateInput(false)]
        [ValidateAntiForgeryToken]
        public ActionResult EditThread(
            Post ThePost,
            int ThreadType,
            int ThreadID,
            string PollText,
            string PollOptions,
            int[] DeleteAttachments,
            bool DeletePollAndVotes=false,
            bool Preview = false,
            string Image=null)
        {
            SetCrumb("Edit Thread");
            Thread TheThread = mbServices.Threads.GetThread(ThreadID);
            Post originalPost = mbServices.Posts.GetPost(ThePost.PostID);
            Poll ThePoll = TheThread.Poll;

            ViewData["UserPermissions"] = new Models.UserPermissions(CurrentUser, TheThread.Forum);
            ViewData["TheThread"] = TheThread;
            ViewData["ThreadID"] = ThreadID;
            ViewData["TheAttachments"] = mbServices.Files.GetPostAttachments(ThePost.PostID);
            ViewData["HasVotes"] = false;

            ValidateThread(ThePost);

            if (TheThread.Poll != null)
            {
                ViewData["HasVotes"] = Repositories.Polls.HasVotes(TheThread.Poll.PollID);
                ViewData["PollText"] = Server.HtmlDecode(TheThread.Poll.Question);
                ViewData["PollOptions"] = Server.HtmlDecode(Repositories.Polls.GetPollOptionsAsText(TheThread.Poll.PollID));
            }

            List<PollOption> PollOpts = new List<PollOption>();

            if (!string.IsNullOrEmpty(PollText))
            {
                if (string.IsNullOrEmpty(PollOptions))
                    ModelState.AddModelError("PollOptions", "The poll must have options");
                else
                {
                    string[] splitOptions = PollOptions.Split(Environment.NewLine.ToCharArray(), StringSplitOptions.RemoveEmptyEntries);

                    if (splitOptions.Count() < 2)
                        ModelState.AddModelError("PollOptions", "Minimum two poll options");
                    else
                    {
                        foreach (string s in splitOptions)
                        {
                            PollOpts.Add(new PollOption
                            {
                                Text =  s
                            });
                        }
                    }
                }
            }

            if (Request.Files.Count > 0)
            {
                ValidatePostedFiles();
            }

            ThePost.Title =  ThePost.Title;

            if (!string.IsNullOrWhiteSpace(ThePost.Text))
            {
                ThePost.ParsedText = mbServices.Posts.ParseBBCodeText(ThePost.Text);

                originalPost.Text = ThePost.Text;
                originalPost.ParsedText = ThePost.ParsedText;
            }

            ViewData["Preview"] = Preview;

            if (Preview)
            {
                return View(ThePost);
            }
            else if (ModelState.IsValid)
            {
                if (ThePoll != null)
                    if ((ThePoll.TotalVotes > 0 && DeletePollAndVotes) || ThePoll.TotalVotes == 0)
                        mbServices.Polls.DeletePoll(ThePoll);


                if (!string.IsNullOrWhiteSpace(PollText))
                    mbServices.Polls.CreatePoll(PollText, PollOptions, ThreadID);


                if (DeleteAttachments != null)
                    mbServices.Files.DeleteAttachments(DeleteAttachments);

                TheThread.Type = ThreadType;
                TheThread.Image = Image;

                originalPost.Title = ThePost.Title;
                originalPost.UseSignature = ThePost.UseSignature;

                mbServices.Threads.UpdateThread(TheThread, originalPost, Request.Files);

                SetSuccess("Thread edited");
                return RedirectToAction("ViewThread", "Board", new { ThreadID = ThePost.ThreadID });
            }
            else
            {
                SetError("Post valdiation errors");
                return View(ThePost);
            }
        }

        [ValidateAntiForgeryToken]
        [HttpPost]
        public ActionResult CastVote(int ThreadID, int PollID, int? PollOptionID)
        {
            Thread TheThread = Repositories.Threads.GetThread(ThreadID);

            if (PollOptionID.HasValue)
            {
                Repositories.Polls.CastVote(PollOptionID.Value, CurrentUser.UserID);
                SetSuccess("Your vote has been cast");
            }
            else
                SetError("Select a vote option to cast a vote");
            return RedirectToAction("ViewThread", "Board", new { ThreadID = ThreadID });
        }

        public ActionResult ThreadReview(int ThreadID)
        {
            return View(Repositories.Posts.GetPosts(ThreadID).OrderByDescending(x => x.Date));
        }

        [mbAuthorize(SpecialPermissions.Administrator, SpecialPermissions.Moderator)]
        public ActionResult DeletePost(int PostID)
        {
            Post ThePost = Repositories.Posts.GetPost(PostID);
            int ThreadID = ThePost.ThreadID;
            int ForumID = ThePost.Thread.ForumID;
            if (ThePost.Thread.FirstPost.PostID == PostID)
            {
                Repositories.Threads.DeleteThread(ThePost.ThreadID);

                Repositories.Forums.SyncForum(ForumID);

                SetSuccess("Thread deleted");
                return RedirectToAction("ViewForum", "Board", new { ForumID = ForumID });
            }
            else
            {
                Repositories.Posts.DeletePost(PostID);

                Repositories.Forums.SyncForum(ForumID);
                Repositories.Threads.SyncThread(ThreadID);
                SetSuccess("Post deleted");
                return RedirectToAction("ViewThread", "Board", new { ThreadID = ThreadID });
            }
        }

        public ActionResult ReportPost(int PostID)
        {
            Post ThePost = Repositories.Posts.GetPost(PostID);
            if (!ThePost.IsReported)
            {
                Repositories.ReportedPosts.CreateReportedPost(new ReportedPost
                {
                    Date = DateTime.UtcNow,
                    PostID = PostID
                });
            }

            SetSuccess("Post reported");
            return RedirectToAction("ViewThread", "Board", new { ThreadID = ThePost.ThreadID });
        }

        public ActionResult DownloadAttachment(int AttachmentID)
        {
            Attachment TheAttach = Repositories.Attachments.GetAttachment(AttachmentID);
            string FullPath = Server.MapPath(Path.Combine("~/Upload/Files", TheAttach.SavedName));
            if (System.IO.File.Exists(FullPath))
            {
                if (!mbServices.Forums.CanDownloadAttachment(TheAttach.Post.Thread.ForumID, CurrentUser.UserID))
                {
                    SetNotice("You don't have permission to download this file");
                    return RedirectToAction("ViewThread", "Board", new { ThreadID = TheAttach.Post.ThreadID });
                }
                TheAttach.Downloaded++;
                Repositories.Attachments.UpdateAttachment(TheAttach);
                return File(FullPath, TheAttach.Type, TheAttach.DownloadName);
            }
            else
            {
                SetNotice("File not found");
                return RedirectToAction("ViewThread", "Board", new { ThreadID = TheAttach.Post.ThreadID });
            }
        }

        [ValidateInput(false)]
        public ActionResult ThreadImages(string Field, string Selected)
        {
            Field = string.IsNullOrWhiteSpace(Field) ? "ThreadImage" : Field;
            ViewData["Field"] = Field;
            ViewData["Selected"] = string.IsNullOrWhiteSpace(Selected) ? "None" : Selected;
            return View(mbServices.ThreadImages.GetThreadImages());
        }

        [NonAction]
        private void ValidatePost(Post ThePost)
        {
            if (string.IsNullOrWhiteSpace(ThePost.Text))
                ModelState.AddModelError("Text", "Message can't be empty");
        }

        [NonAction]
        private void ValidateThread(Post ThePost)
        {
            if (string.IsNullOrWhiteSpace(ThePost.Title))
                ModelState.AddModelError("Title", "Title can't be empty");
            else if (ThePost.Title.Length > 50)
                ModelState.AddModelError("Title", "Title can be no more than 50 characters");
            ValidatePost(ThePost);
        }

        [NonAction]
        private void ValidatePostedFiles()
        {
            int MaxFileSize = SiteConfig.MaxFileSize.ToInt();
            for (int i = 0; i < Request.Files.Count; i++)
            {
                HttpPostedFileBase f = Request.Files[i];
                if (f.ContentLength > 0)
                {
                    if (f.ContentLength > MaxFileSize * 1024)
                        ModelState.AddModelError("FileSize", "Max file size is " + MaxFileSize);
                    if (!Repositories.FileTypes.IsAllowedFileType(Path.GetExtension(f.FileName)))
                        ModelState.AddModelError("FileType", "File type not accepted");
                }
            }
        }
    }
}